homework 1, version 0
Submission by: SOLUTIONS (SOLUTIONS@mit.edu)
Homework 1 - convolutions
18.S191
, fall 2020
This notebook contains built-in, live answer checks! In some exercises you will see a coloured box, which runs a test case on your code, and provides feedback based on the result. Simply edit the code, run it, and the check runs again.
For MIT students: there will also be some additional (secret) test cases that will be run as part of the grading process, and we will look at your notebook and write comments.
Feel free to ask questions!
"SOLUTIONS"
"SOLUTIONS"
Let's create a package environment:
Activating new project at `/tmp/jl_jKLOp0`
We set up Images.jl again:
Updating registry at `~/.julia/registries/General.toml` Resolving package versions... Updating `/tmp/jl_jKLOp0/Project.toml` [82e4d734] + ImageIO v0.6.9 [6218d12a] + ImageMagick v1.4.0 [916415d5] + Images v0.26.2 Updating `/tmp/jl_jKLOp0/Manifest.toml` [621f4979] + AbstractFFTs v1.5.0 [79e6a3ab] + Adapt v3.7.2 [66dad0bd] + AliasTables v1.1.3 [ec485272] + ArnoldiMethod v0.4.0 [4fba245c] + ArrayInterface v7.5.1 [13072b0f] + AxisAlgorithms v1.1.0 [39de3d68] + AxisArrays v0.4.7 [62783981] + BitTwiddlingConvenienceFunctions v0.1.6 [fa961155] + CEnum v0.5.0 [2a0fbf3d] + CPUSummary v0.2.6 [aafaddc9] + CatIndices v0.2.2 [d360d2e6] + ChainRulesCore v1.25.1 [9e997f8a] + ChangesOfVariables v0.1.9 [fb6a15b2] + CloseOpenIntervals v0.1.13 [aaaa29a8] + Clustering v0.15.8 [35d6a980] + ColorSchemes v3.29.0 [3da002f7] + ColorTypes v0.12.0 [c3611d14] + ColorVectorSpace v0.11.0 [5ae59095] + Colors v0.13.0 [bbf7d656] + CommonSubexpressions v0.3.1 [34da2185] + Compat v4.16.0 [ed09eef8] + ComputationalResources v0.3.2 [187b0558] + ConstructionBase v1.5.8 [150eb455] + CoordinateTransformations v0.6.3 [adafc99b] + CpuId v0.3.1 [dc8bdbbb] + CustomUnitRanges v1.0.2 [9a962f9c] + DataAPI v1.16.0 [864edb3b] + DataStructures v0.18.20 [163ba53b] + DiffResults v1.1.0 [b552c78f] + DiffRules v1.15.1 [b4f34e82] + Distances v0.10.12 [ffbed154] + DocStringExtensions v0.9.3 [4f61f5a4] + FFTViews v0.3.2 [7a1cc6ca] + FFTW v1.8.1 [5789e2e9] + FileIO v1.17.0 [53c48c17] + FixedPointNumbers v0.8.5 [f6369f11] + ForwardDiff v0.10.38 [a2bd30eb] + Graphics v1.1.3 [86223c79] + Graphs v1.12.0 [2c695a8d] + HistogramThresholding v0.3.1 [3e5b6fbb] + HostCPUFeatures v0.1.17 [615f187c] + IfElse v0.1.1 [2803e5a7] + ImageAxes v0.6.12 [c817782e] + ImageBase v0.1.7 [cbc4b850] + ImageBinarization v0.3.1 [f332f351] + ImageContrastAdjustment v0.3.12 [a09fc81d] + ImageCore v0.10.5 [89d5987c] + ImageCorners v0.1.3 [51556ac3] + ImageDistances v0.2.17 [6a3955dd] + ImageFiltering v0.7.9 [82e4d734] + ImageIO v0.6.9 [6218d12a] + ImageMagick v1.4.0 [bc367c6b] + ImageMetadata v0.9.10 [787d08f9] + ImageMorphology v0.4.5 [2996bd0c] + ImageQualityIndexes v0.3.7 [80713f31] + ImageSegmentation v1.8.4 [4e3cecfd] + ImageShow v0.3.8 [02fcd773] + ImageTransformations v0.10.1 [916415d5] + Images v0.26.2 [9b13fd28] + IndirectArrays v1.0.0 [d25df0c9] + Inflate v0.1.5 [1d092043] + IntegralArrays v0.1.6 [a98d9a8b] + Interpolations v0.15.1 [8197267c] + IntervalSets v0.7.10 [3587e190] + InverseFunctions v0.1.17 [92d709cd] + IrrationalConstants v0.2.4 [c8e1da08] + IterTools v1.4.0 [033835bb] + JLD2 v0.5.11 [692b3bcd] + JLLWrappers v1.7.0 [b835a17e] + JpegTurbo v0.1.5 [10f19ff3] + LayoutPointers v0.1.17 [8cdb02fc] + LazyModules v0.3.1 [2ab3a3ac] + LogExpFunctions v0.3.28 [bdcacae8] + LoopVectorization v0.12.171 [1914dd2f] + MacroTools v0.5.15 [d125e4d3] + ManualMemory v0.1.8 [dbb5928d] + MappedArrays v0.4.2 [626554b9] + MetaGraphs v0.8.0 [e1d29d7a] + Missings v1.2.0 [e94cdb99] + MosaicViews v0.3.4 [77ba4419] + NaNMath v1.0.3 [b8a86587] + NearestNeighbors v0.4.21 [f09324ee] + Netpbm v1.1.1 [6fe1bfb0] + OffsetArrays v1.15.0 [52e1d378] + OpenEXR v0.3.3 [bac558e1] + OrderedCollections v1.8.0 [f57f5aa1] + PNGFiles v0.4.4 [5432bcbf] + PaddedViews v0.5.12 [d96e819e] + Parameters v0.12.3 [eebad327] + PkgVersion v0.3.3 [1d0040c9] + PolyesterWeave v0.2.2 [f27b6e38] + Polynomials v4.0.19 [aea7be01] + PrecompileTools v1.2.1 [21216c6a] + Preferences v1.4.3 [92933f4c] + ProgressMeter v1.10.2 [43287f4e] + PtrArrays v1.3.0 [4b34888f] + QOI v1.0.1 [94ee1d12] + Quaternions v0.7.6 [b3c3ace0] + RangeArrays v0.3.2 [c84ed2f1] + Ratios v0.4.5 [c1ae055f] + RealDot v0.1.0 [3cdcf5f2] + RecipesBase v1.3.4 [189a3867] + Reexport v1.2.2 [dee08c22] + RegionTrees v0.3.2 [ae029012] + Requires v1.3.1 [6038ab10] + Rotations v1.7.1 [fdea26ae] + SIMD v3.7.1 [94e857df] + SIMDTypes v0.1.0 [476501e8] + SLEEFPirates v0.6.43 [efcf1570] + Setfield v1.1.2 [699a6c99] + SimpleTraits v0.9.4 [47aef6b3] + SimpleWeightedGraphs v1.4.0 [45858cf5] + Sixel v0.1.3 [a2af1166] + SortingAlgorithms v1.2.1 [276daf66] + SpecialFunctions v2.5.0 [cae243ae] + StackViews v0.1.1 [aedffcd0] + Static v0.8.9 [0d7ed370] + StaticArrayInterface v1.6.0 [90137ffa] + StaticArrays v1.9.13 [1e83bf80] + StaticArraysCore v1.4.3 [82ae8749] + StatsAPI v1.7.0 [2913bbd2] + StatsBase v0.34.4 [62fd8b95] + TensorCore v0.1.1 [8290d209] + ThreadingUtilities v0.5.2 [731e570b] + TiffImages v0.11.3 [06e1c1a7] + TiledIteration v0.5.0 [3bb67fe8] + TranscodingStreams v0.11.3 [3a884ed6] + UnPack v1.0.2 [3d5dd08c] + VectorizationBase v0.21.71 [e3aaa7dc] + WebP v0.1.3 [efce3f68] + WoodburyMatrices v1.0.0 [f5851436] + FFTW_jll v3.3.10+3 [61579ee1] + Ghostscript_jll v9.55.0+4 [59f7168a] + Giflib_jll v5.2.3+0 [c73af94c] + ImageMagick_jll v7.1.1+1 [905a6f67] + Imath_jll v3.1.11+0 [1d5cc7b8] + IntelOpenMP_jll v2025.0.4+0 [aacddb02] + JpegTurbo_jll v3.1.1+0 [88015f11] + LERC_jll v3.0.0+1 [d4300ac3] + Libgcrypt_jll v1.11.0+0 [7e76a0d4] + Libglvnd_jll v1.7.0+0 [7add5ba3] + Libgpg_error_jll v1.51.1+0 [94ce4f54] + Libiconv_jll v1.18.0+0 [89763e89] + Libtiff_jll v4.4.0+0 [d3a379c0] + LittleCMS_jll v2.12.0+0 [856f044c] + MKL_jll v2025.0.1+1 [18a262bb] + OpenEXR_jll v3.2.4+0 [643b3616] + OpenJpeg_jll v2.4.0+0 [efe28fd5] + OpenSpecFun_jll v0.5.6+0 [02c8fc9c] + XML2_jll v2.13.6+1 [aed1982a] + XSLT_jll v1.1.42+0 [4f6342f7] + Xorg_libX11_jll v1.8.6+3 [0c0b7dd1] + Xorg_libXau_jll v1.0.12+0 [a3789734] + Xorg_libXdmcp_jll v1.1.5+0 [1082639a] + Xorg_libXext_jll v1.3.6+3 [14d82f49] + Xorg_libpthread_stubs_jll v0.1.2+0 [c7cfdc94] + Xorg_libxcb_jll v1.17.0+3 [c5fb5394] + Xorg_xtrans_jll v1.5.1+0 [3161d3a3] + Zstd_jll v1.5.7+1 [b53b4c65] + libpng_jll v1.6.47+0 [075b6546] + libsixel_jll v1.10.5+0 [c5f90fcd] + libwebp_jll v1.4.0+0 [1317d2d5] + oneTBB_jll v2022.0.0+0 [0dad84c5] + ArgTools [56f22d72] + Artifacts [2a0f44e3] + Base64 [ade2ca70] + Dates [8ba89e20] + Distributed [f43a241f] + Downloads [7b1f6079] + FileWatching [9fa8497b] + Future [b77e0a4c] + InteractiveUtils [4af54fe1] + LazyArtifacts [b27032c2] + LibCURL [76f85450] + LibGit2 [8f399da3] + Libdl [37e2e46d] + LinearAlgebra [56ddb016] + Logging [d6f4376e] + Markdown [a63ad114] + Mmap [ca575930] + NetworkOptions [44cfe95a] + Pkg [de0858da] + Printf [3fa0cd96] + REPL [9a3f8284] + Random [ea8e919c] + SHA [9e88b42a] + Serialization [1a1011a3] + SharedArrays [6462fe0b] + Sockets [2f01184e] + SparseArrays [10745b16] + Statistics [4607b0f0] + SuiteSparse [fa267f1f] + TOML [a4e569a6] + Tar [8dfed614] + Test [cf7118a7] + UUIDs [4ec0a83e] + Unicode [e66e0078] + CompilerSupportLibraries_jll [deac9b47] + LibCURL_jll [29816b5a] + LibSSH2_jll [c8ffd9c3] + MbedTLS_jll [14a3606d] + MozillaCACerts_jll [4536629a] + OpenBLAS_jll [05823500] + OpenLibm_jll [83775a58] + Zlib_jll [8e850b90] + libblastrampoline_jll [8e850ede] + nghttp2_jll [3f19e933] + p7zip_jll
Exercise 1 - Manipulating vectors (1D images)
A Vector
is a 1D array. We can think of that as a 1D image.
0.5
0.4
0.3
0.2
0.1
0.0
0.7
0.0
0.7
0.9
Exerise 1.1
👉 Make a random vector random_vect
of length 10 using the rand
function.
0.620701
0.472725
0.555847
0.882684
0.234533
0.95594
0.758358
0.468873
0.821036
0.522793
Got it!
Yay ❤
Hint
You can find out more about any function (like rand
) by creating a new cell and typing:
?rand
Once the Live Docs are open, you can select any code to learn more about it. It might be useful to leave it open all the time, and get documentation while you type code.
👉 Make a function mean
using a for
loop, which computes the mean/average of a vector of numbers.
mean (generic function with 1 method)
2.0
Got it!
Great! 🎉
👉 Define m
to be the mean of random_vect
.
0.6293489284489368
Got it!
Great! 🎉
👉 Write a function demean
, which takes a vector x
and subtracts the mean from each value in x
.
demean (generic function with 1 method)
Let's check that the mean of the demean(random_vect)
is 0:
Due to floating-point round-off error it may not be exactly 0.
3.3306690738754695e-17
Exercise 1.2
👉 Generate a vector of 100 zeros. Change the center 20 elements to 1.
create_bar (generic function with 1 method)
Got it!
Great! 🎉
Exercise 1.3
👉 Write a function that turns a Vector
of Vector
s into a Matrix
.
vecvec_to_matrix (generic function with 1 method)
2×2 Matrix{Int64}:
1 3
2 4
Got it!
Great!
👉 Write a function that turns a Matrix
into aVector
of Vector
s .
matrix_to_vecvec (generic function with 1 method)
6
8
7
9
Got it!
Great! 🎉
colored_line (generic function with 2 methods)
Exercise 2 - Manipulating images
In this exercise we will get familiar with matrices (2D arrays) in Julia, by manipulating images. Recall that in Julia images are matrices of RGB
color objects.
Let's load a picture of Philip again.
"/tmp/jl_wcFqmy"
Hi there Philip
Exercise 2.1
👉 Write a function mean_colors
that accepts an object called image
. It should calculate the mean (average) amounts of red, green and blue in the image and return a tuple (r, g, b)
of those means.
mean_colors (generic function with 1 method)
0.600389
0.547441
0.479491
Got it!
Great!
Exercise 2.2
👉 Look up the documentation on the floor
function. Use it to write a function quantize(x::Number)
that takes in a value
quantize (generic function with 3 methods)
0.2
0.9
Got it!
Let's move on to the next section.
Exercise 2.3
👉 Write the second method of the function quantize
, i.e. a new version of the function with the same name. This method will accept a color object called color
, of the type AbstractRGB
.
Write the function in the same cell as quantize(x::Number)
from the last exercise. 👆
Here, ::AbstractRGB
is a type annotation. This ensures that this version of the function will be chosen when passing in an object whose type is a subtype of the AbstractRGB
abstract type. For example, both the RGB
and RGBX
types satisfy this.
The method you write should return a new RGB
object, in which each component (
Exercise 2.4
👉 Write a method quantize(image::AbstractMatrix)
that quantizes an image by quantizing each pixel in the image. (You may assume that the matrix is a matrix of color objects.)
Write the function in the same cell as quantize(x::Number)
from the last exercise. 👆
Let's apply your method!
Exercise 2.5
👉 Write a function invert
that inverts a color, i.e. sends
invert (generic function with 1 method)
Let's invert some colors:
Can you invert the picture of Philip?
Exercise 2.6
👉 Write a function noisify(x::Number, s)
to add randomness of intensity clamp
function, but you should write your own function myclamp(x)
.)
noisify (generic function with 3 methods)
Hint
The rand
function generates (uniform) random floating-point numbers between
👉 Write the second method noisify(c::AbstractRGB, s)
to add random noise of intensity
Write the function in the same cell as noisify(x::Number)
from the last exercise. 👆
👉 Write the third method noisify(image::AbstractMatrix, s)
to noisify each pixel of an image.
Write the function in the same cell as noisify(x::Number)
from the last exercise. 👆
👉 For which noise intensity does it become unrecognisable?
You may need noise intensities larger than 1. Why?
The image is unrecognisable with intensity 3
The information density is lower than the pixel density - you can visually combine blurry neighbouring pixels to still form an image.
Resolving package versions... Updating `/tmp/jl_jKLOp0/Project.toml` [7f904dfe] + PlutoUI v0.7.23 Updating `/tmp/jl_jKLOp0/Manifest.toml` [6e696c72] + AbstractPlutoDingetjes v1.3.2 [47d2ed2b] + Hyperscript v0.0.4 [ac1192a8] + HypertextLiteral v0.9.5 [b5f81e59] + IOCapture v0.2.5 [682c06a0] + JSON v0.21.4 [69de0a69] + Parsers v2.8.1 [7f904dfe] + PlutoUI v0.7.23 [410a4b4d] + Tricks v0.1.10
decimate (generic function with 2 methods)
Exercise 3 - Convolutions
As we have seen in the videos, we can produce cool effects using the mathematical technique of convolutions. We input one image
Conceptually we think of Matrix
of color objects, and we may need to take that into account. Ideally, however, we should write a generic function that will work for any type of data contained in the matrix.
A convolution works on a small window of an image, i.e. a region centered around a given point
The result of the convolution over a given window, centred at the point
To get started let's restrict ourselves to convolutions in 1D. So a window is just a 1D region from
Let's create a vector v
of random numbers of length n=100
.
100
0.781471
0.608673
0.368508
0.127647
0.420141
0.894021
0.452184
0.698126
0.692316
0.818016
0.631991
0.994341
0.987175
0.177033
0.116108
0.359603
0.390385
0.10833
0.831412
0.176603
0.688553
0.96456
0.394274
0.717424
0.658518
0.866922
0.791145
0.826947
0.172851
0.0988334
Feel free to experiment with different values!
Exercise 3.1
You've seen some colored lines in this notebook to visualize arrays. Can you make another one?
👉 Try plotting our vector v
using colored_line(v)
.
Try changing n
and v
around. Notice that you can run the cell v = rand(n)
again to regenerate new random values.
Exercise 3.2
We need to decide how to handle the boundary conditions, i.e. what happens if we try to access a position in the vector v
beyond 1:n
. The simplest solution is to assume that
A better solution is to use the closest value that is inside the vector. Effectively we are extending the vector and copying the extreme values into the extended positions. (Indeed, this is one way we could implement this; these extra positions are called ghost cells.)
👉 Write a function extend(v, i)
that checks whether the position 1:n
. If so, return the v
; otherwise, return the nearest end value.
extend (generic function with 1 method)
Some test cases:
0.7814714745396361
0.7814714745396361
0.0988333788117135
Extended with 0:
Extended with your extend
:
Got it!
Well done!
Exercise 3.3
👉 Write a function blur_1D(v, l)
that blurs a vector v
with a window of length l
by averaging the elements within a window from
blur_1D (generic function with 1 method)
Exercise 3.4
👉 Apply the box blur to your vector v
. Show the original and the new vector by creating two cells that call colored_line
. Make the parameter
Hint
Have a look at Exercise 2 to see an example of adding interactivity with a slider. You can read the Interactivity and the PlutoUI sample notebooks (right click -> Open in new tab) to learn more.
Exercise 3.5
The box blur is a simple example of a convolution, i.e. a linear function of a window around each point, given by
where
Again, we need to take care about what happens if
👉 Write a function convolve_vector(v, k)
that performs this convolution. You need to think of the vector
convolve_vector (generic function with 1 method)
Hint
l = (length(k) - 1) ÷ 2
11
110
1100
11000
20000
Edit the cell above, or create a new cell with your own test cases!
Got it!
Good job!
Exercise 3.6
👉 Write a function gaussian_kernel
.
pascal (generic function with 1 method)
gaussian_kernel (generic function with 1 method)
1.0
0.25
0.5
0.25
0.0625
0.25
0.375
0.25
0.0625
0.015625
0.09375
0.234375
0.3125
0.234375
0.09375
0.015625
0.00390625
0.03125
0.109375
0.21875
0.273438
0.21875
0.109375
0.03125
0.00390625
0.000976562
0.00976562
0.0439453
0.117188
0.205078
0.246094
0.205078
0.117188
0.0439453
0.00976562
0.000976562
Let's test your kernel function!
0.620701
0.472725
0.555847
0.882684
0.234533
0.95594
0.758358
0.468873
0.821036
0.522793
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
Exercise 4 - Convolutions of images
Now let's move to 2D images. The convolution is then given by a kernel matrix
where the sum is over the possible values of
Exercise 4.1
👉 Write a function extend_mat
that takes a matrix M
and indices i
and j
, and returns the closest element of the matrix.
extend_mat (generic function with 1 method)
Hint
num_rows, num_columns = size(M)
Let's test it!
Extended with 0
:
Extended with your extend
:
Got it!
Well done!
Exercise 4.2
👉 Implement a function convolve_image(M, K)
.
convolve_image (generic function with 1 method)
Hint
num_rows, num_columns = size(K)
Let's test it out! 🎃
3×3 Matrix{Float64}:
0.0 0.0 0.0
0.5 0.0 0.5
0.0 0.0 0.0
Edit K_test
to create your own test case!
You can create all sorts of effects by choosing the kernel in a smart way. Today, we will implement two special kernels, to produce a Gaussian blur and a Sobel edge detect filter.
Make sure that you have watched the lecture about convolutions!
Exercise 4.3
👉 Apply a Gaussian blur to an image.
Hint
Can we just copy the 1D code? What is different in 2D?
with_gaussian_blur (generic function with 1 method)
Let's make it interactive. 💫
Another cell defining gauss_camera_image contains errors.
MethodError: no method matching getindex(::Missing, ::String)
Here is what happened, the most recent locations are first:
- process_raw_camera_data
(raw_camera_data::Missing) from Other cell: line 13# So to get the red values for each pixel, we take every 4th value, starting at
# the 1st:
reds_flat = UInt8.(raw_camera_data["data"][1:4:end])
greens_flat = UInt8.(raw_camera_data["data"][2:4:end])
blues_flat = UInt8.(raw_camera_data["data"][3:4:end])
- Show more...
Exercise 4.4
👉 Create a Sobel edge detection filter.
with_sobel_edge_detect (generic function with 1 method)
Another cell defining sobel_camera_image contains errors.
MethodError: no method matching getindex(::Missing, ::String)
Here is what happened, the most recent locations are first:
- process_raw_camera_data
(raw_camera_data::Missing) from Other cell: line 13# So to get the red values for each pixel, we take every 4th value, starting at
# the 1st:
reds_flat = UInt8.(raw_camera_data["data"][1:4:end])
greens_flat = UInt8.(raw_camera_data["data"][2:4:end])
blues_flat = UInt8.(raw_camera_data["data"][3:4:end])
- Show more...
Exercise 5 - Lecture transcript
(MIT students only)
Please see the Piazza post for transcript document here.
👉 Which lines of the transcripts did you edit?
Lecture 1, lines 10-50 (for example)
hint (generic function with 1 method)
almost (generic function with 1 method)
still_missing (generic function with 2 methods)
keep_working (generic function with 2 methods)
Great!
Yay ❤
Great! 🎉
Well done!
Keep it up!
Good job!
Awesome!
You got the right answer!
Let's move on to the next section.
correct (generic function with 2 methods)
not_defined (generic function with 1 method)
camera_input (generic function with 1 method)
process_raw_camera_data (generic function with 1 method)